﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Project.Database.Repository
{
    public partial class DatabaseRepository
    {
        #region Properties

        private const double CLICK_DELAY_SECONDS = 60;

        #endregion

        #region Query Methods

        public List<Tuple<DateTime, List<Click>>> GetClicksHistorgram(IQueryable<Click> clicks)
        {
            List<Tuple<DateTime, List<Click>>> list = new List<Tuple<DateTime, List<Click>>>();
            if(clicks.Count() == 0)
                return list;
            DateTime date = clicks.First().Timestamp.Date;
            List<Click> clist = new List<Click>();
            
            foreach (Click c in clicks)
            {
                if (c.Timestamp.Date.Equals(date))
                {
                    clist.Add(c);
                }
                else
                {
                    list.Add(new Tuple<DateTime, List<Click>>(date.Date, clist));
                    clist = new List<Click>();
                    date = c.Timestamp.Date;
                    clist.Add(c);
                }
            }
            if (clist.Count() > 0)
            {
                list.Add(new Tuple<DateTime, List<Click>>(date.Date, clist));
            }
            return list;   
        }

        public IQueryable<Click> GetLastMonthsClicksForAdvertOnBlog(int advertID, int blogID)
        {
            DateTime lastmonth = DateTime.Now.AddMonths(-1);
            return from click in entities.Clicks
                   where click.AdvertID == advertID && click.BlogID == blogID && click.Timestamp.CompareTo(lastmonth) >= 0
                   orderby click.Timestamp descending
                   select click;
        }

        public IQueryable<Click> GetLastWeeksClicksForAdvertOnBlog(int advertID, int blogID)
        {
            DateTime lastweek = DateTime.Now.AddDays(-7);
            return from click in entities.Clicks
                   where click.AdvertID == advertID && click.BlogID == blogID && click.Timestamp.CompareTo(lastweek) > 0
                   orderby click.Timestamp descending
                   select click;
        }

        public IQueryable<Click> GetTodaysClicksForAdvertOnBlog(int advertID, int blogID)
        {
            DateTime today = DateTime.Today;
            return from click in entities.Clicks
                   where click.AdvertID == advertID && click.BlogID == blogID && click.Timestamp.CompareTo(today) >= 0
                   orderby click.Timestamp descending
                   select click;
        }

        public IQueryable<Click> GetAllClicksForAdvertOnBlog(int advertID, int blogID)
        {
            return from click in entities.Clicks
                   where click.AdvertID == advertID && click.BlogID == blogID
                   orderby click.Timestamp ascending
                   select click;
        }

        public int GetClickCountForAdvertOnBlog(int advertID, int blogID)
        {
            return GetAllClicksForAdvertOnBlog(advertID, blogID).Count();
        }

        public Click GetLastClickForAdvertOnBlog(int advertID, int blogID)
        {
            return (from click in entities.Clicks
                   where click.AdvertID == advertID && click.BlogID == blogID
                   orderby click.Timestamp descending
                    select click).FirstOrDefault();
        }

        public Click GetLastClickForAdvertOnBlog(int advertID, int blogID, string IP)
        {
            return (from click in entities.Clicks
                    where click.AdvertID == advertID && click.BlogID == blogID && click.IP == IP
                    orderby click.Timestamp descending
                    select click).FirstOrDefault();
        }

        #endregion

        #region Insert/Delete

        private void AddClick(Click click)
        {
            entities.Clicks.AddObject(click);
        }

        public void CreateClick(int advertID, int blogID, string IP, DateTime timestamp)
        {
            //TODO check inputs

            Blog blog = GetBlog(blogID);
            if(blog == null)
                throw new ArgumentException("The blog URL provided is invalid. Please check the value and try again.");
            if(!AdvertExists(GetAdvert(advertID)))
                 throw new ArgumentException("Cannot add click, the advert '"+advertID+"' does not exist!");

            Click click = new Click()
            {
                BlogID = blog.ID,
                AdvertID = advertID,
                IP = IP,
                Timestamp = timestamp
            };

            try
            {
                AddClick(click);
                // Immediately persist the user data
                Save();
            }
            catch (ArgumentException ae)
            {
                throw ae;
            }
            catch (Exception)
            {
                throw new ArgumentException("The authentication provider returned an error. Please verify your entry and try again. " +
                    "If the problem persists, please contact your system administrator.");
            }
        }

        #endregion

        #region Helper Methods

        public bool IsClickValid(int advertID, int blogID, string IP, DateTime timestamp)
        {
            Blog blog = GetBlog(blogID);
            if(blog == null)
                return false;

            Click click = GetLastClickForAdvertOnBlog(advertID,blog.ID,IP);
            if (click == null)
                return true;

            if (click.Timestamp.AddSeconds(CLICK_DELAY_SECONDS).CompareTo(timestamp) < 0)
            {
                return true;
            }

            return false;
        }

        #endregion
    }
}